zynq实现udp网络的数据包的上传(zynq7z035)(ps端)

您所在的位置:网站首页 lwip udp组播 能发送不能接收 zynq实现udp网络的数据包的上传(zynq7z035)(ps端)

zynq实现udp网络的数据包的上传(zynq7z035)(ps端)

2024-07-16 15:04:34| 来源: 网络整理| 查看: 265

1、前面的文件的建立,参考另外的一篇blog

https://blog.csdn.net/weixin_42066185/article/details/106421611

2、直接进入udp建立的那个部分

对于udp的建立,在2018版本的vivado 上的,有相关对应的例程,然而,我是用的版本的是2017,当前并无相关udp的通信例程,因此,我主要参考的都是如下的参考的链接:

https://blog.csdn.net/FPGADesigner/article/details/88746532

https://blog.csdn.net/FPGADesigner/article/details/88748846(最主要参考)

https://blog.csdn.net/FPGADesigner/article/details/88751502

3、主函数建立过程

(1) 整体建立过程

/* * 设置开发板MAC地址 * 开启中断系统 * 设置本地IP地址 * 初始化lwIP * 添加网络接口 * 设置默认网络接口 * 启动网络 * 初始化TCP或UDP连接(自定义函数) * */

(2)设置开发板的mac地址

struct netif *netif; struct ip_addr ipaddr, netmask, gw; /* the mac address of the board. this should be unique per board */ //设定开发板的MAC地址 unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 }; netif = &server_netif;

热555555555555555555555(3) 初始化平台,开启中断

init_platform(); //开启中断系统,这个里面设定的时定时中断

(4)初始化网卡的ip

/* initliaze IP addresses to be used */ IP4_ADDR(&ipaddr, 192, 168, 127, 202); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 127, 254); print_app_header(); lwip_init();

(5)  初始化lwip, 添加网卡的netlif , 并且将这个网卡设置成默认网卡

/* Add network interface to the netif_list, and set it as default */ if (!xemac_add(echo_netif, &ipaddr, &netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) { xil_printf("Error adding N/W interface\n\r"); return -1; } netif_set_default(echo_netif); /* now enable interrupts */ platform_enable_interrupts(); /* specify that the network if is up */ netif_set_up(echo_netif); print_ip_settings(&ipaddr, &netmask, &gw);

(6)初始化udp

/* start the application (web server, rxtest, txtest, etc..) */ // start_application(); xil_printf("初始化udp网络/r/n"); user_udp_init(); //初始化UDP

(7) 循环初始化

while (1) { xil_printf("we are sending \r\n"); /* 将MAC队列中的包传输的LwIP/IP栈中 */ xemacif_input(netif); // if (udp_connected_flag) { //发送 sleep(1); // xil_printf("we are in if nei\r\n"); udp_printf(); // } } /* never reached */ cleanup_platform();

整个主函数文件内容:

/****************************************************************************** * * Copyright (C) 2017 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ #include #include "xparameters.h" #include "netif/xadapter.h" #include "platform.h" #include "platform_config.h" #include "lwipopts.h" #include "xil_printf.h" #include "sleep.h" #include "sleep.h" #include "sys_intr.h" #include "lwip/init.h" #include "lwip/inet.h" #include "xil_cache.h" //#include "ip_addr.h" #include "user_udp.h" #if LWIP_DHCP==1 #include "lwip/dhcp.h" extern volatile int dhcp_timoutcntr; #endif static XScuGic Intc; //GIC extern unsigned udp_connected_flag; extern volatile int TcpFastTmrFlag; extern volatile int TcpSlowTmrFlag; // #define DEFAULT_IP_ADDRESS "192.168.127.202" #define DEFAULT_IP_MASK "255.255.255.0" #define DEFAULT_GW_ADDRESS "192.168.127.254" //#define DEFAULT_IP_ADDRESS "115.156.163.175" //#define DEFAULT_IP_MASK "255.255.254.0" //#define DEFAULT_GW_ADDRESS "115.156.163.254" void platform_enable_interrupts(void); void start_application(void); void print_app_header(void); #if defined (__arm__) && !defined (ARMR5) #if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || \ XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 int ProgramSi5324(void); int ProgramSfpPhy(void); #endif #endif #ifdef XPS_BOARD_ZCU102 #ifdef XPAR_XIICPS_0_DEVICE_ID int IicPhyReset(void); #endif #endif struct netif server_netif; static void print_ip(char *msg, ip_addr_t *ip) { print(msg); xil_printf("%d.%d.%d.%d\r\n", ip4_addr1(ip), ip4_addr2(ip), ip4_addr3(ip), ip4_addr4(ip)); } static void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw) { print_ip("Board IP: ", ip); print_ip("Netmask : ", mask); print_ip("Gateway : ", gw); } static void assign_default_ip(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw) { int err; xil_printf("Configuring default IP %s \r\n", DEFAULT_IP_ADDRESS); err = inet_aton(DEFAULT_IP_ADDRESS, ip); if (!err) xil_printf("Invalid default IP address: %d\r\n", err); err = inet_aton(DEFAULT_IP_MASK, mask); if (!err) xil_printf("Invalid default IP MASK: %d\r\n", err); err = inet_aton(DEFAULT_GW_ADDRESS, gw); if (!err) xil_printf("Invalid default gateway address: %d\r\n", err); } int main(void) { /* * 设置开发板MAC地址 * 开启中断系统 * 设置本地IP地址 * 初始化lwIP * 添加网络接口 * 设置默认网络接口 * 启动网络 * 初始化TCP或UDP连接(自定义函数) * */ struct netif *netif; struct ip_addr ipaddr, netmask, gw; /* the mac address of the board. this should be unique per board */ //设定开发板的MAC地址 unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 }; netif = &server_netif; #if defined (__arm__) && !defined (ARMR5) #if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || \ XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 xil_printf("we are in here\r\n"); ProgramSi5324(); ProgramSfpPhy(); #endif #endif // Xil_ICacheEnable(); // Xil_DCacheEnable(); init_platform(); //开启中断系统,这个里面设定的时定时中断 // Init_Intr_System(&Intc); // Setup_Intr_Exception(&Intc); //定义一个网卡 netif = &server_netif; /*两种方案实现对网卡ip、子网掩码、以及网关*/ //方案1 // IP_ADDR(&ipaddr, 192, 168, 127, 202); // IP_ADDR(&netmask, 255, 255, 255, 0); // IP_ADDR(&gw, 192, 168, 127, 254); assign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw)); xil_printf("\r\n\r\n"); xil_printf("-----lwIP RAW Mode UDP Server Application-----\r\n"); /* initialize lwIP */ lwip_init(); xil_printf("we have finnished lwip init"); /* Add network interface to the netif_list, and set it as default */ if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) { xil_printf("Error adding N/W interface\r\n"); return -1; } xil_printf("before the the default set"); netif_set_default(netif); //将当前的网卡设定成默认的网卡 xil_printf("after the default set"); /* now enable interrupts */ platform_enable_interrupts(); //开启之前设定的中断 /* specify that the network if is up */ netif_set_up(netif); //启动之前所设定的网络 print_ip_settings(&(netif->ip_addr), &(netif->netmask), &(netif->gw)); xil_printf("\r\n"); /* print app header */ //print_app_header(); /* start the application*/ //start_application(); //初始化udp,启动服务器 user_udp_init(); xil_printf("\r\n"); while (1) { xil_printf("we are sending \r\n"); /* 将MAC队列中的包传输的LwIP/IP栈中 */ xemacif_input(netif); // if (udp_connected_flag) { //发送 sleep(1); // xil_printf("we are in if nei\r\n"); udp_printf(); // } } /* never reached */ cleanup_platform(); return 0; }

 

 

3.1 user_udp.c 文件 #include "user_udp.h" //--------------------------------------------------------- // 变量定义 //--------------------------------------------------------- struct udp_pcb *connected_pcb = NULL; static struct pbuf *pbuf_to_be_sent = NULL; char *send_buff = "udploWorld"; //待发送字符 int *send_buffint = 100; struct ip_addr ipaddr; static unsigned local_port = 5002; //本地端口 static unsigned remote_port = 8080; //远程端口 //--------------------------------------------------------- // UDP连接初始化函数 //--------------------------------------------------------- int user_udp_init(void) { struct udp_pcb *pcb; err_t err; /* 创建UDP控制块 */ pcb = udp_new(); if (!pcb) { xil_printf("Error Creating PCB.\r\n"); return -1; } /* 绑定本地端口 */ err = udp_bind(pcb, IP_ADDR_ANY, local_port); if (err != ERR_OK) { xil_printf("Unable to bind to port %d\r\n", local_port); return -2; } /* 设置远程地址 */ IP4_ADDR(&ipaddr, 192, 168, 127, 200); // IP4_ADDR(&ipaddr, 192, 168, 1, 101); // IP4_ADDR(&ipaddr, 115, 156, 162, 123); // IP4_ADDR(&ipaddr, 115, 156, 162, 76); connected_pcb = pcb; /* 申请pbuf资源 */ pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_ROM); memset(pbuf_to_be_sent->payload, 0, 10); // memcpy(pbuf_to_be_sent->payload, (u8 *)send_buff, 4); return 0; } //--------------------------------------------------------- // UDP发送数据函数 //--------------------------------------------------------- void udp_printf(void) { err_t err; struct udp_pcb *tpcb = connected_pcb; if (!tpcb) { xil_printf("error connect.\r\n"); } // // send_buff[0] ='0'; // send_buff[1] = '1'; // send_buff[2] = '2'; // send_buff[3] = '3'; // send_buff[4] = '4'; // send_buff[5] = '5'; // send_buff[6] = '6'; // send_buff[7] = '7'; // send_buff[8] = '8'; // send_buff[9] = '9'; *send_buff = "0123456789"; // memset(pbuf_to_be_sent->payload, 0, 10); memcpy(pbuf_to_be_sent->payload, (u8 *)send_buff, 10); /* 发送字符串 */ err = udp_sendto(tpcb, pbuf_to_be_sent, &ipaddr, remote_port); if (err != ERR_OK) { // xil_printf("Error on udp send : %d\r\n", err); return; } } void udp_senddata(int data) { err_t err; struct udp_pcb *tpcb = connected_pcb; if (!tpcb) { xil_printf("error connect.\r\n"); } // data =100; *send_buffint = data; memcpy(pbuf_to_be_sent->payload, send_buffint, 2); xil_printf("we are sending here:%d\r\n",*send_buffint); /* 发送字符串 */ err = udp_sendto(tpcb, pbuf_to_be_sent, &ipaddr, remote_port); if (err != ERR_OK) { // xil_printf("Error on udp send : %d\r\n", err); return; } } 3.2 user_udp.h /* * usr_udp.h * * Created on: 2020年1月16日 * Author: Scottar */ #ifndef SRC_USER_UDP_H_ #define SRC_USER_UDP_H_ #include "lwip/err.h" #include "lwip/udp.h" #include "lwip/init.h" #include "lwipopts.h" #include "lwip/err.h" #include "lwipopts.h" #include "netif/xadapter.h" #include "xil_printf.h" int user_udp_init(void); void udp_printf(void); void udp_senddata(int data); #endif /* SRC_USER_UDP_H_ */ 4. 过程测试 4.1 上位机接收程序 reveiver_url = "ipc://11_Router" socketzmq = context.socket(zmq.ROUTER) socketzmq.set_hwm(HWM_VAL) sendinglist=[] client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client_socket.bind(("192.168.127.200", 8080)) print('we have connected to the tcp data send server!---port is :', port) packagenum = 0 start_time_perf = time.perf_counter() start_time_process = time.process_time() count = 0 # 实际上应当启用的市多线程来做这些事情的 # 每一个线程要做的事情就是接收对应的内容 # 我想epics里面做的也是基本想同样的事情 ---最后写一个自动化的脚本多线程 start_flag = True while True: b, addr = client_socket.recvfrom(10) print('I',count) if count==1000000: break count = count + 1 # timestample = str(datetime.datetime.now()).encode() # b = b + timestample # # sendinglist.append(b) print(packagenum) end_time_perf = time.perf_counter() end_time_process = time.process_time() print('Receiving port is: ', port) print('Package num:', count) print('receing time cost:', end_time_perf - start_time_perf) # socketzmq.close() 4.2 以100us 发送的速率

(1)下位机的测试程序

(2)测试结果如下:

 

4.3 以10us 的速度进行发送。

(1)下位机的测试的程序

(2) 测试结果

上位机的测试结果:

(3) 上位机去掉print 打印进行结果测试

第一次测试结果

第二次测试结果:

第三次测试结果:

 

 

4.4  设定下位机的上传延时为5us

(1)上位机数据接收程序以及下位机发程序

(2)测试结果:

第一次测试结果:

 

第二次测试结果:

第三次测试结果:

 

4.5  设定在7us下的的测试结果

 

测试结论:

对于udp来说,以10us的速度进行上传,上位机的接收速度没有办法完全达到10us 的接受速度, 这样的原因,可能是由与下位机在发送的时候设定的程序的延时就是10us,但是,由于其调用udp的发送程序,其也会出现相应的时间的消耗,所以整体出现了接收1M个数据包会出现较多的耗时,经过不断的测试,可以发现将下位机的发送程序设定的延时在7us的情况下,上位机接收到1M个数据包,所消耗的时间十分接近10s,也就是100k/s的上传的速度。

 

4.6   关于udp数据上传的丢包情况验证 4.6.1 下位机的上传的的速度设定为100us

(1)上位机的测试代码

(2)以下位机以100us的速度 ,通过udp进行上传。上位机接收到数据后,打上时间标签。

(3) 测试结果如下:

可见,对于这样的速度的udp来说,也基本不会出现丢包的问题。

 

4.6.2下位机上传的速度设定为10us

(1) 下位机数据上传代码:

下面的主要代码是提前设定好了,数据包发送的速度是10us,然后每个数字每10个一轮回

(2)上位机测试代码:

(3) 测试结果

通过上面的测试结果,我们可以得出,数据包的传输会出现相对较多的丢包情况。

4.6.3 设定下位机的上传速度是7us

测试打时间标签的耗时影响。

(1)下位机测试程序代码:

(2)上位机测试程序

(3) 测试结果

第一次测试结果

第二次测试结果

第三次测试结果

第四次测试结果:

 

(4) 判断丢包情况

通过上面的测试结果,可以看到会丢包情况。

5 整体接收与转发的测试:

 

5.1 在另一台linux 电脑上进行测试数据的接收与打时标(接收1M数据的测试)

(1) 测试接收代码:

(2) 测试接收耗时:

第一次测试:

第二次测试:

 

5.2 测试接收和转发1M个数据包的耗时

(1)上位机测试代码

 

(2) 测试结果:

          

 

5.3  中间的数据监测接收模块(累积10个数据后发送)(这一节的测试是没有考虑pub和sub之间的连接的耗时所导致的数据接收,其他地方都进行了考虑)

(1) 上位机接收代码:

 

(2)中间测试结果

   

(3) 测试结论

    中间累积10个数据包再进行发送,可以大量减少中间数据中转的情况,但是可以看到实际的数据丢包的情况,其接近1%的丢包率。这个丢包率应该是建立在pub与sub之间的数据包丢包,应当,出现这样的原因显然是由于pub-sub的定义的客户端和服务器不合适,我们通过现在将pub定义成客户端,连接好sub服务器之后,再进行数据的发送。

 

5.4 中间累积10个数据包后进行数据发送(并且修改成pub 是客户端)

(1)第一次测试结果:

(2)第二次测试结果

(3) 第三次测试结果:

(4) 第四次测试结果:

 

(5) 第五次测试结果:

 

ps:以上所有的测试结果中,第三层次的测试耗时,都与第二层次的耗时基本一样,如下:

(6) 第六次测试结果

5.5 测试结论

    通过上面的测试过程与结果,我们可以得到zmq 的发送函数zmq.send 函数频繁的调用,会出现比较消耗系统的资源,占用一定的时间。因此,当我们累积10个之后,再进行数据的发送,在这样的情况下,理论上,可以将由于数据发送的耗时降低10倍

 

6  验证数据包之间打上时间标签的时间间隔。 6.1 验证原理

应当首先默认下位机的上传的速度是能够大概在每隔10us 上传一次数据,我们需要验证上位机的打时标的前后两个数据包的时间,保证其前后两个数据包的时间个间隔在可接受的范围内,通过上述的测试的结果,我们可以计算每个数据包之间平均间隔。

对于10.68s,对应1M个数据包,即每个数据包的时间为如下:10.68us,即约10us。

 10.68/1000000 1.068e-05

但是实际上,两个数据包之间的数据的间隔是总是变化的,因此,我们将这样的数据包通过单上时间标签,然后通过通过对包的数据格式的解析之后,将其存储到数据库当中,然后对之后存储进去的数据进行实际的验证。

6.2 验证实际两个数据包之间的间隔

---------------updata----on 2020-0601-------------

6.2.1第三层的数据接收中加入实际的数据的存储之后,系统耗时加长

(1)测试结果

中间数据监测层耗时:

第三层的数据解析与存储层次的耗时:

(2) 第二次的测试结果

中间监测层的耗时:

 

第三层的数据的解析与存储层次的耗时:

(3) 第三次测试结果

中间数据接收和监测层的耗时:

第三层数据解析与存储层的耗时:

 

6.2.2 查看系统中的数据存储的数据

 

 

 

 

 

6.2.3 结论:

  通过上面存入到数据库当中,的时间标签间隔,可以发现很多数据之间的监测大概都在13us左右,由于我们接收的数据的时间为13s,因此,每个数据包的时间的间隔约为13s/1M=13us。

  根据上一小节展示的结果,我们可以看到结果是存在一定成都上的数据包的丢失,但是丢失很少。这也是udp通讯协议不可避免的地方。

 

 

 

6.3 系统资源的监测与分析 6.3.1 系统资源监测

(1) 在数据传输过程中的系统监测图:

(2)监测结论

>>> 100000*(64)*8/1024/1024 48.828125

当下位机设备通过100k/s 的速度进行上传数据包的时候,我们可以通过将udp的头部,ip头部,数据长度加在一起,可以大致计算出实际上传的速度的大小。

对于tcp,udp ip mac 的帧格式,请参考:https://www.cnblogs.com/OctoptusLian/p/8580052.html

udp+ip的头部整体的字节数为:8个字节(udp头部) +  20字节(ip)+ mac(14) =42字节,我们再额外加上10个字节的数据,我们可以得到52个字节。由于mac会帮助我们进行数据的填充,所以实际还是应当按照64个字节进行计算,结果如上所示,并且也可验证出我们的结果的正确性。

 

6.3.2  耗时解决方案

    占用了更多的系统的资源,此时对于udp的数据的接收来说,我们可以通过降低udp数据的发送延时,来提高其发送的速度,从而使得实际的这边的数据的接收的时间的间隔更加短一些。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6.0 debug 说明(中间偶尔出现的bug的)

中间的某些时刻有可能会出现,上位机接收不到的情况,很有可能是由于phy芯片自动协商的问题,这个时候,由于笔记本的电脑采用一般都是千兆的网卡, 但是有时候由于介质的原因可能协商到百兆,就会出现意向不到问题,总之,要确定自己的网卡协调后的网速应当是1Gb,如下图

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭